home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / unix / lq-text / 2951 < prev   
Encoding:
Text File  |  1992-08-26  |  44.4 KB  |  1,729 lines

  1. #! /bin/sh
  2. : part 03
  3. echo x - lq-text/src/UseHash
  4. cat > lq-text/src/UseHash << 'barefoot_choirboy'
  5. # Run this if you want to use the BSD hash package (ozmahash)
  6. cd src
  7. cp ozmahash/*.h h
  8. cp ozmahash/ndbm.h h/ozmahash.h
  9. barefoot_choirboy
  10. chmod +x UseHash
  11. echo x - lq-text/src/liblqtext/Defaults.c 1>&2
  12. sed 's/^X//' >lq-text/src/liblqtext/Defaults.c <<'@@@End of lq-text/src/liblqtext/Defaults.c'
  13. X/* Defaults.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
  14. X * This code is NOT in the public domain.
  15. X * See the file COPYRIGHT for full details.
  16. X *
  17. X * $Id: Defaults.c,v 1.7 90/10/06 00:11:37 lee Rel1-10 $
  18. X *
  19. X * $Log:    Defaults.c,v $
  20. X * Revision 1.7  90/10/06  00:11:37  lee
  21. X * Prepared for first beta release.
  22. X * 
  23. X * Revision 1.6  90/08/29  21:46:25  lee
  24. X * Alpha release.
  25. X * 
  26. X * Revision 1.5  90/08/09  19:16:08  lee
  27. X * *** empty log message ***
  28. X * 
  29. X * Revision 1.4  90/04/21  17:26:26  lee
  30. X * now passes gcc -W (before Canada...)
  31. X * 
  32. X * Revision 1.3  90/03/23  17:58:57  lee
  33. X * Integrated with globals.h and added a few more comments.
  34. X * Also fixed a bug whereby the configuration file over-rode both
  35. X * command-line options and environment variables!
  36. X * 
  37. X * Revision 1.2  90/03/20  20:52:38  lee
  38. X * removed some globals...
  39. X * 
  40. X *
  41. X */
  42. X
  43. X#define DefineThem /* turn externs off so we do initialisations here */
  44. X# include "globals.h" /* defines and declarations for database filenames */
  45. X#undef DefineThem
  46. X#undef EXTERN
  47. X#include <fcntl.h>
  48. X#include <errno.h>
  49. X#ifdef SYSV
  50. Xextern int _filbuf(); /* this must appear before stdio.h is included... */
  51. X#endif
  52. X#include <stdio.h>
  53. X#include <malloc.h>
  54. X#include <ctype.h>
  55. X#include "emalloc.h"
  56. X#include <sys/types.h>
  57. X#include "fileinfo.h"
  58. X#include "wordinfo.h"
  59. X#include "phrase.h"
  60. X
  61. X/* $Id: Defaults.c,v 1.7 90/10/06 00:11:37 lee Rel1-10 $
  62. X *
  63. X * This file is part of nx-text, Liam Quin's text retrieval package.
  64. X *
  65. X * Defaults.c -- set up filenames etc. from defaults + cmd line + env.
  66. X *
  67. X * -DUNDERHOME is used here, as is DEFAULTCOMMONWORDS, etc. from Makefile.
  68. X * See comments in Makefile.
  69. X *
  70. X * $Log:    Defaults.c,v $
  71. X * Revision 1.7  90/10/06  00:11:37  lee
  72. X * Prepared for first beta release.
  73. X * 
  74. X * Revision 1.6  90/08/29  21:46:25  lee
  75. X * Alpha release.
  76. X * 
  77. X * Revision 1.5  90/08/09  19:16:08  lee
  78. X * *** empty log message ***
  79. X * 
  80. X * Revision 1.4  90/04/21  17:26:26  lee
  81. X * now passes gcc -W (before Canada...)
  82. X * 
  83. X * Revision 1.3  90/03/23  17:58:57  lee
  84. X * Integrated with globals.h and added a few more comments.
  85. X * Also fixed a bug whereby the configuration file over-rode both
  86. X * command-line options and environment variables!
  87. X * 
  88. X * Revision 1.2  90/03/20  20:52:38  lee
  89. X * removed some globals...
  90. X * 
  91. X *
  92. X */
  93. X
  94. X/* System and Library calls used in this function:
  95. X *
  96. X */
  97. Xextern int open(), close();
  98. Xextern void exit();
  99. X
  100. Xextern int atoi(), strcmp(), strlen();
  101. X#ifndef tolower
  102. X extern int tolower();
  103. X#endif
  104. Xextern char *strcpy();
  105. Xextern void perror();
  106. Xextern int ReadCommonWords(), IsDir();
  107. Xint cknatstr();
  108. Xstatic int NextChar();
  109. Xstatic void ReadDefaultFile();
  110. X
  111. X
  112. Xtypedef enum {
  113. X    FW_Cmdline,
  114. X    FW_Envvar,
  115. X    FW_Default, /* use the default */
  116. X    FW_File, /* from the config file */
  117. X    FW_None /* don't use any at all */
  118. X} t_FromWhere;
  119. X
  120. Xstatic t_FromWhere DirFromWhere = FW_Default;
  121. Xstatic t_FromWhere CommonFromWhere = FW_Default;
  122. Xstatic t_FromWhere DocFromWhere = FW_Default;
  123. X
  124. Xextern int MakeDocPath(); /* hand it DOCPATH... */
  125. Xextern int AsciiTrace;
  126. X
  127. Xchar *mkdbm();
  128. Xchar *joinstr3();
  129. X
  130. X/* should PCM_HalfCase be in globals.h??? */
  131. Xt_PhraseCaseMatch PhraseMatchLevel = PCM_HalfCase;
  132. X
  133. Xvoid
  134. XSetDefaults(argc, argv)
  135. X    int argc;
  136. X    char **argv;
  137. X{
  138. X    extern char *getenv();
  139. X    extern char *progname;
  140. X    char *p;
  141. X
  142. X    /* main() should have set progname.  If it didn't. we don't strip
  143. X     * the leading / as this is (I hope!) a testing and not a production
  144. X     * version... and an early test at that!
  145. X     */
  146. X    if (!progname || !*progname) progname = argv[0];
  147. X
  148. X    /* loop over arguments, looking for
  149. X     * -d -- set directory for database
  150. X     * -c -- common words file
  151. X     *
  152. X     * don't use getopts, as we'll be using that later in main(),
  153. X     * and it doesn't like being called twice.
  154. X     * As a result, main() should ignore the z: option.
  155. X     */
  156. X    while (--argc > 0) {
  157. X    if (**++argv == '-' || **argv == '+') {
  158. X        char TurnOn = (**argv == '-');
  159. X
  160. X        switch((*argv)[1]) {
  161. X        case 'm': /* precise matching */
  162. X        argv[0][1] = 'z'; /* so it gets ignored by getopt */
  163. X
  164. X        if (!*(p = &argv[0][2])) {
  165. X            if (argc > 1) {
  166. X            argc--; argv++;
  167. X            p = (*argv);
  168. X            } else {
  169. X            fprintf(stderr,
  170. X            "%s: -m must be followed by a, h or p; see -x\n",
  171. X                                progname);
  172. X            exit(1);
  173. X            }
  174. X        }
  175. X        if (p[1]) {
  176. X            fprintf(stderr,
  177. X            "%s: -m must be followed by a, h or p, not \"%s\"\n",
  178. X                                progname, p);
  179. X        }
  180. X
  181. X        switch (*p) {
  182. X        case 'p': /* precise */
  183. X            PhraseMatchLevel = PCM_SameCase;
  184. X            break;
  185. X        case 'h': /* heuristic */
  186. X            PhraseMatchLevel = PCM_HalfCase;
  187. X            break;
  188. X        case 'a': /* any, approxmate */
  189. X            PhraseMatchLevel = PCM_AnyCase;
  190. X            break;
  191. X        default:
  192. X            fprintf(stderr,
  193. X            "%s: -m must be followed by \"p\", \"h\" or \"a\";\n",
  194. X                                    progname);
  195. X            fprintf(stderr,
  196. X            "use %s -xv for more explanation.\n", progname);
  197. X            exit(1);
  198. X        }
  199. X        break;
  200. X
  201. X        case 'v': /* -v is the same as -t1 */
  202. X        argv[0][1] = 'Z'; /* so it gets ignored by getopt */
  203. X        ++AsciiTrace;
  204. X        break;
  205. X        case 't': /* trace level */
  206. X        argv[0][1] = 'z'; /* so it gets ignored by getopt */
  207. X        if (argv[0][2] != '\0') {
  208. X            p = &argv[0][2];
  209. X        } else {
  210. X            if (argc > 1) {
  211. X            argc--;
  212. X            p = (*++argv);
  213. X            } else {
  214. X            p = "1";
  215. X            }
  216. X        }
  217. X        if (cknatstr(p)) {
  218. X            AsciiTrace = atoi(p);
  219. X        } else {
  220. X            fprintf(stderr, "%s: -t: \"%s\" is not a number\n",
  221. X                                    progname, p);
  222. X            exit(1);
  223. X        }
  224. X        if (AsciiTrace <= 0) AsciiTrace = 1;
  225. X        fprintf(stderr, "%s: trace level set to %d\n",
  226. X                                progname, AsciiTrace);
  227. X
  228. X        break;
  229. X        case 'c': /* common file */
  230. X        if (TurnOn) {
  231. X            CommonFromWhere = FW_Cmdline;
  232. X            argv[0][1] = 'z'; /* so it gets ignored by getopt */
  233. X            if ((*argv)[2] != '\0') {
  234. X            CommonWordFile = &(*argv[2]);
  235. X            } else {
  236. X            if (argc > 1) {
  237. X                CommonWordFile = argv[1];
  238. X                argc--; argv++;
  239. X            } else {
  240. X                fprintf(stderr,
  241. X                "%s: -c option must be followed by a filename",
  242. X                                    progname);
  243. X                exit(1);
  244. X            }
  245. X            }
  246. X        } else { /* Turn off, +c, may be undocumented right now */
  247. X            CommonFromWhere = FW_None;
  248. X            break;
  249. X        }
  250. X        break;
  251. X        case 'd':
  252. X        argv[0][1] = 'z'; /* so it gets ignored by getopt */
  253. X        DirFromWhere = FW_Cmdline;
  254. X        if (argv[0][2] != '\0') {
  255. X            DatabaseDir = &argv[0][2];
  256. X        } else {
  257. X            if (argc > 1) {
  258. X            DatabaseDir = argv[1];
  259. X            argc--; argv++;
  260. X            } else {
  261. X            /* @error */
  262. X            fprintf(stderr,
  263. X                "%s: %cd must be followed by a directory name",
  264. X                        progname, TurnOn ? '-' : '+');
  265. X            exit(1);
  266. X            }
  267. X        }
  268. X        break;
  269. X        } /* end switch */
  270. X    } else {
  271. X        /* not an option, so stop looking */
  272. X        break;
  273. X    }
  274. X    } /* end while */
  275. X
  276. X    /* now we have parsed the command line arguments, so look for the
  277. X     * default directory
  278. X     */
  279. X    if (DirFromWhere == FW_Default) {
  280. X    char *t;
  281. X
  282. X    if ((t = getenv("LQTEXTDIR")) != (char *) 0) {
  283. X        DatabaseDir = emalloc(strlen(t) + 1);
  284. X        (void) strcpy(DatabaseDir, t);
  285. X        DirFromWhere = FW_Envvar;
  286. X    } else {
  287. X#ifdef UNDERHOME
  288. X        char *home = getenv("HOME");
  289. X
  290. X        if (home) {
  291. X        DatabaseDir = joinstr3(home, "/", UNDERHOME);
  292. X        if (!IsDir(DatabaseDir)) {
  293. X            fprintf(stderr,
  294. X                "%s: database directory \"%s\" inaccessible.\n",
  295. X                progname, DatabaseDir);
  296. X            exit(1);
  297. X        }
  298. X        } else {
  299. X        fprintf(stderr, "%s: can't find your login directory ($HOME)\n",
  300. X                    progname);
  301. X        exit(1);
  302. X        }
  303. X#endif /* UNDERHOME*/
  304. X        /* in either case it's the default... */
  305. X        DirFromWhere = FW_Default;
  306. X    }
  307. X    }
  308. X
  309. X    if (!DatabaseDir || !*DatabaseDir) {
  310. X    /* This can happen if there is no default, or if the user types
  311. X     * lqword -d ""
  312. X     * just to be malicious :-)
  313. X     */
  314. X    fprintf(stderr,
  315. X    "%s: You must give a database directory with -d or $LQTEXTDIR\n",
  316. X            progname);
  317. X    fprintf(stderr, "        use %s -xv for more details.\n", progname);
  318. X    exit(1);
  319. X    }
  320. X
  321. X    /* IsDir is in DocPath.c -- perhaps this should be, too. */
  322. X    if (!IsDir(DatabaseDir)) {
  323. X    char *msg = (char *) 0;
  324. X
  325. X    switch (DirFromWhere) {
  326. X    case FW_Cmdline:
  327. X        msg = " (specified with the -d option)";
  328. X        break;
  329. X    case FW_Envvar:
  330. X        msg = " (from $LQTEXTDIR)";
  331. X        break;
  332. X    }
  333. X    fprintf(stderr, "%s: \"%s\"%s is not a directory.\n",
  334. X                    progname, DatabaseDir, msg ? msg : " ");
  335. X    exit(1);
  336. X    }
  337. X
  338. X    /* set default filenames */
  339. X#define IfNot(x, y) ((x) ? (x) : (y))
  340. X
  341. X    FileIndex = mkdbm(DatabaseDir, IfNot(FileIndex, FILEINDEX));
  342. X    WordIndex = mkdbm(DatabaseDir, IfNot(WordIndex, WORDINDEX));
  343. X
  344. X    DataBase = joinstr3(DatabaseDir, "/", IfNot(DataBase, DATABASE));
  345. X    FidFile = joinstr3(DatabaseDir, "/", IfNot(FidFile, FIDFILE));
  346. X    WidFile = joinstr3(DatabaseDir, "/", IfNot(WidFile, WIDFILE));
  347. X    WidIndexFile =
  348. X        joinstr3(DatabaseDir, "/", IfNot(WidIndexFile, WIDINDEXFILE));
  349. X
  350. X    ReadDefaultFile();
  351. X
  352. X    if (AsciiTrace) {
  353. X    fprintf(stderr, "%s: lqtext directory \"%s\"\n",progname,DatabaseDir);
  354. X    }
  355. X
  356. X    if (CommonFromWhere == FW_Default) {
  357. X    char *c = getenv("LQCOMMON");
  358. X
  359. X    if (c) {
  360. X        CommonWordFile = emalloc(strlen(c) + 1);
  361. X        (void) strcpy(CommonWordFile, c);
  362. X        CommonFromWhere = FW_Envvar;
  363. X    }
  364. X    }
  365. X
  366. X    if (CommonFromWhere != FW_None && CommonWordFile && *CommonWordFile) {
  367. X    extern int errno;
  368. X    int c;
  369. X
  370. X    if (*CommonWordFile != '/') {
  371. X        CommonWordFile = joinstr3(DatabaseDir, "/", CommonWordFile);
  372. X    }
  373. X
  374. X    if ((c = open(CommonWordFile, O_RDONLY, 0)) < 0) {
  375. X        if (CommonFromWhere != FW_Default) {
  376. X        int e = errno;
  377. X        char *msg = " ";
  378. X
  379. X        switch (CommonFromWhere) {
  380. X        case FW_Cmdline:
  381. X            msg = " (from the -c option)";
  382. X            break;
  383. X        case FW_Envvar:
  384. X            msg = " (from $COMMONWORDS)";
  385. X            break;
  386. X        }
  387. X
  388. X        fprintf(stderr,"%s: can't read common-word file%s ",progname,msg);
  389. X        errno = e;
  390. X        if (errno) {
  391. X            perror(CommonWordFile);
  392. X        } else {
  393. X            fprintf(stderr, "\"%s\"\n", CommonWordFile);
  394. X        }
  395. X        exit(1);
  396. X        }
  397. X        CommonWordFile = (char *) 0;
  398. X    } else {
  399. X        (void) close(c); /* it's OK */
  400. X    }
  401. X    }
  402. X
  403. X    if ((p = getenv("DOCPATH")) != (char *) 0) {
  404. X    switch (DocFromWhere) {
  405. X    case FW_File:
  406. X        if (AsciiTrace > 1) {
  407. X        fprintf(stderr, "%s: DOCPATH (%s) overrides %s (%s)\n",
  408. X#ifdef CONFIGFILE
  409. X                progname, p, CONFIGFILE, DocPath
  410. X#else
  411. X                progname, p, "README", DocPath
  412. X#endif
  413. X        );
  414. X        }
  415. X        efree(DocPath);
  416. X        /* FALL THROUGH */
  417. X    case FW_Default:
  418. X    default: /* ? */
  419. X        DocPath = emalloc((unsigned) (strlen(p) + 1));
  420. X        (void) strcpy(DocPath, p);
  421. X        DocFromWhere = FW_Envvar;
  422. X        break;
  423. X    }
  424. X    }
  425. X
  426. X    if (!DocPath || !*DocPath) {
  427. X    DocPath = ".";
  428. X    }
  429. X
  430. X#define SetOrNot(s) ( (s && *s) ? s : (s ? "[empty]" : "[null]" ) )
  431. X
  432. X    /* this is always here -- it's only checked once, and is actually
  433. X     * rather useful.
  434. X     */
  435. X    if (AsciiTrace > 2) {
  436. X    fprintf(stderr, "%s: CommonWordFile = \"%s\"\n", progname,
  437. X        SetOrNot(CommonWordFile));
  438. X    fprintf(stderr, "%s: DatabaseDir = \"%s\"\n", progname,
  439. X        SetOrNot(DatabaseDir));
  440. X    fprintf(stderr, "%s: DocPath  = \"%s\"\n", progname,
  441. X        SetOrNot(DocPath));
  442. X    fprintf(stderr, "%s: FileIndex = \"%s\"\n", progname,
  443. X        SetOrNot(FileIndex));
  444. X    fprintf(stderr, "%s: WordIndex = \"%s\"\n", progname,
  445. X        SetOrNot(WordIndex));
  446. X    fprintf(stderr, "%s: DataBase = \"%s\"\n", progname,
  447. X        SetOrNot(DataBase));
  448. X    fprintf(stderr, "%s: FidFile = \"%s\"\n", progname,
  449. X        SetOrNot(FidFile));
  450. X    fprintf(stderr, "%s: WidFile = \"%s\"\n", progname,
  451. X        SetOrNot(WidFile));
  452. X    fprintf(stderr, "%s: WidIndexFile = \"%s\"\n", progname,
  453. X        SetOrNot(WidIndexFile));
  454. X    }
  455. X
  456. X    (void) MakeDocPath(DocPath);
  457. X    /* DocPath is no longer needed, so getenv() can be called again now */
  458. X
  459. X    if (CommonWordFile && *CommonWordFile) {
  460. X    (void) ReadCommonWords(CommonWordFile);
  461. X    }
  462. X}
  463. X
  464. Xvoid
  465. XDefaultUsage()
  466. X{
  467. X    fprintf(stderr, "\
  468. X    -c file    -- ignore words that are listed in the namd file\n\
  469. X    -d dir    -- use the lq-text database in the named directory\n\
  470. X    -m c    -- set matching criteria -- c is \"p\", \"h\" or \"a\"\n");
  471. X    if (AsciiTrace) {
  472. X    fprintf(stderr, "\
  473. X           -m p  uses precise matching, where CaSe is significant;\n\
  474. X           -m h  uses heuristic matching, which is the default, and\n\
  475. X           -m a  uses approximate matching.\n");
  476. X    }
  477. X
  478. X    fprintf(stderr, "\n\
  479. X    -t N    -- set trace level t N (default is zero)\n\
  480. X    -x    -- print %s explanation\n\
  481. X    -xv    -- print %s explanation\n\
  482. X    -V    -- print version information\n\
  483. X    -v    -- be verbose (same as -t 1)\n",
  484. X            AsciiTrace ? "a shorter" : "this",
  485. X            AsciiTrace ? "this" : "a longer");
  486. X    if (AsciiTrace) {
  487. X    fprintf(stderr, "\
  488. XThe current database directory is \"%s\";\n\
  489. X%s will search the path \"%s\" for documents.\n", DatabaseDir, progname, DocPath);
  490. X    }
  491. X}
  492. X
  493. X/* This should be in smalldb.c I think */
  494. Xchar *
  495. Xmkdbm(root, prefix)
  496. X    char *root; /* /tmp/lqtext */
  497. X    char *prefix; /* wordlist, --> /tmp/lqtext.{dir,pag} for dbm */
  498. X{
  499. X#if DBMCREAT == 0
  500. X    extern int errno;
  501. X#endif
  502. X    /* Although ndbm will create files automatically, gdbm and dbm will
  503. X     * not, so we do that here.
  504. X     * Also, it might take a while to get to here, so it will be a lot
  505. X     * better if we get an error message now.
  506. X     */
  507. X    char *p = joinstr3(root, "/", prefix);
  508. X
  509. X#if DBMCREAT == 0
  510. X    q = joinstr3(p, ".", "dir");
  511. X    errno = 0; /* paranoia */
  512. X
  513. X    if ((i = open(q)) < 0 && errno == ENOENT) {
  514. X    i = open(q, O_CREAT|O_RDWR, 0666); /* rw-rw-rw & umask */
  515. X
  516. X    if (i < 0) {
  517. X        fprintf(stderr, "%s: can't create \"%s\"\n", progname, q);
  518. X        (void) exit(1);
  519. X    }
  520. X
  521. X    (void) close(i);
  522. X    }
  523. X    (void) strcpy(&q[strlen(q) - 3], "pag");
  524. X
  525. X    if ((i = open(q)) < 0 && errno == ENOENT) {
  526. X    i = open(q, O_CREAT|O_RDWR, 0666); /* rw-rw-rw & umask */
  527. X
  528. X    if (i < 0) {
  529. X        fprintf(stderr, "%s: can't create \"%s\"\n", progname, q);
  530. X        (void) exit(1);
  531. X    }
  532. X
  533. X    (void) close(i);
  534. X    }
  535. X
  536. X    (void) efree(q);
  537. X
  538. X#endif /*DBMCREAT*/
  539. X
  540. X    return p; /* the prefix for dbm, not the whole path */
  541. X}
  542. X
  543. X/* this belongs in string.c or something */
  544. Xchar *
  545. Xjoinstr3(a, b, c)
  546. X    char *a, *b, *c;
  547. X{
  548. X    char *p;
  549. X    int i = strlen(a), j = (b[0] != '\0' && b[1] == '\0') ? 1 : strlen(b);
  550. X
  551. X    p = emalloc(i + j + strlen(c) + 1);
  552. X    /* ASSERT: p != 0 */
  553. X    (void) strcpy(p, a);
  554. X    (void) strcpy(&p[i], b);
  555. X    (void) strcpy(&p[i + j], c);
  556. X
  557. X    return p;
  558. X}
  559. X
  560. X#define LCNOMAP 0 /* Token -- leave case alone */
  561. X#define LCMAP 1  /* map to lower case */
  562. X
  563. Xstatic int RMLine = 0;
  564. X
  565. Xstatic void
  566. XReadDefaultFile()
  567. X{
  568. X    extern int errno;
  569. X
  570. X    static char *NextToken(); /* see below */
  571. X#ifdef CONFIGFILE
  572. X    char *ReadMe = joinstr3(DatabaseDir, "/", CONFIGFILE);
  573. X#else
  574. X    char *ReadMe = joinstr3(DatabaseDir, "/", "README");
  575. X#endif
  576. X    FILE *fp;
  577. X    char *Token;
  578. X
  579. X
  580. X    /* This is paranoid... */
  581. X    if (!ReadMe || !*ReadMe) {
  582. X    fprintf(stderr, "%s: Internal: %s: %d: ReadMe %s\n",
  583. X        progname, __FILE__, __LINE__, SetOrNot(ReadMe));
  584. X    exit(1);
  585. X    }
  586. X
  587. X    errno = 0;
  588. X    if ((fp = fopen(ReadMe, "r")) == (FILE *) 0) {
  589. X    if (errno == EPERM) {
  590. X        fprintf(stderr,
  591. X        "%s: Warning: you don't have permission to read \"%s\"\n",
  592. X                            progname, ReadMe);
  593. X    } else if (AsciiTrace) {
  594. X        int e = errno;
  595. X
  596. X        fprintf(stderr, "%s: warning: can't open config file ", progname);
  597. X        errno = e;
  598. X        perror(ReadMe);
  599. X    }
  600. X    return;
  601. X    }
  602. X
  603. X    /* Read README up to an "end" line, ignoring lines starting with # */
  604. X
  605. X    while ((Token = NextToken(fp, ReadMe, LCMAP)) != (char *) 0) {
  606. X    if (STREQ(Token, "end")) goto finish;
  607. X    if (STREQ(Token, "common")) {
  608. X        if (!(Token = NextToken(fp, ReadMe, LCNOMAP))) {
  609. X        fprintf(stderr, "%s: %s %d: unexpected eof at common file\n",
  610. X                progname, ReadMe, RMLine);
  611. X        exit(1);
  612. X        } else if (CommonFromWhere == FW_Default) {
  613. X            CommonWordFile = emalloc((unsigned) (strlen(Token) + 1));
  614. X            (void) strcpy(CommonWordFile, Token);
  615. X            CommonFromWhere = FW_File;
  616. X        }
  617. X    } else if (STREQ(Token, "path") || STREQ(Token, "docpath")) {
  618. X        if (!(Token = NextToken(fp, ReadMe, LCNOMAP))) {
  619. X        fprintf(stderr, "%s: %s: %d: unexpected eof at common file\n",
  620. X                progname, ReadMe, RMLine);
  621. X        exit(1);
  622. X        } else {
  623. X        DocPath = emalloc((unsigned) (strlen(Token) + 1));
  624. X        (void) strcpy(DocPath, Token);
  625. X        DocFromWhere = FW_File;
  626. X        }
  627. X    } else {
  628. X        fprintf(stderr, "%s: \"%s\": %d: token(\"%s\") unexpected\n",
  629. X                progname, ReadMe, RMLine, Token);
  630. X        exit(1);
  631. X    }
  632. X    } /* while */
  633. X
  634. Xfinish:
  635. X    (void) fclose(fp);
  636. X    return;
  637. X}
  638. X
  639. Xstatic char *
  640. XNextToken(fd, Name, Map)
  641. X    FILE *fd;
  642. X    char *Name;
  643. X    int Map;
  644. X{
  645. X    int ch;
  646. X    static char buf[50];
  647. X    register char *q = buf;
  648. X    int InQuote = 0;
  649. X    int OriginalMap = Map;
  650. X
  651. X    while ((ch = NextChar(fd, Name, Map)) != EOF) {
  652. X    switch (ch) {
  653. X    case '"': case '\'':
  654. X        if (q == buf && !InQuote) InQuote = ch;
  655. X        else if (ch == InQuote) {
  656. X        *q = '\0';
  657. X        if (AsciiTrace > 10) {
  658. X            fprintf(stderr, "RM[%s] ", buf);
  659. X        }
  660. X        return buf;
  661. X        }
  662. X        Map = 0; /* no case conversion inside strings */
  663. X        break;
  664. X    case '\\':
  665. X        if ((ch = NextChar(fd, Name, Map)) == EOF) {
  666. X        fprintf(stderr, "%s: %s; %d: EOF after \\ unexpected!\n",
  667. X                            progname, Name, RMLine);
  668. X        exit(1);
  669. X        }
  670. X        *q++ = ch;
  671. X        break;
  672. X    case ' ':
  673. X    case '\n':
  674. X        if (InQuote) {
  675. X        fprintf(stderr, "%s: %s: %d: missing quote -->%s<--\n",
  676. X                        progname, Name, RMLine, InQuote);
  677. X        exit(1);
  678. X        }
  679. X        *q = '\0';
  680. X        if (q > buf) return buf;
  681. X        else return NextToken(fd, Name, OriginalMap);
  682. X        /*NOTREACHED*/
  683. X        break;
  684. X    default:
  685. X        *q++ = ch;
  686. X    }
  687. X    }
  688. X    if (q > buf) {
  689. X    fprintf(stderr, "%s: %s: %d: unexpected end of file\n",
  690. X                            progname, Name, RMLine);
  691. X    exit(1);
  692. X    }
  693. X    return (char *) 0;
  694. X}
  695. X
  696. Xstatic int
  697. XNextChar(fd, Name, Map)
  698. X    FILE *fd;
  699. X    char *Name;
  700. X    int Map;
  701. X{
  702. X    int ch;
  703. X
  704. X    while ((ch = getc(fd)) != EOF) {
  705. X    switch (ch) {
  706. X    case '#':
  707. X        do {
  708. X        if ((ch = getc(fd)) == EOF) {
  709. X            fprintf(stderr, "%s: %s: %d: unexpected end of file\n",
  710. X                progname, Name, RMLine);
  711. X            exit(1);
  712. X        }
  713. X        } while (ch != '\n');
  714. X        /* ASSERT: ch == '\n' */
  715. X        ++RMLine;
  716. X        break;
  717. X    case '\n':
  718. X        ++RMLine; 
  719. X        if (!Map) return ch;
  720. X        /* else FALL THROUGH */
  721. X    case ' ': case '\t': case '\f': case '\r':
  722. X        if (!Map) {
  723. X        return ' ';
  724. X        }
  725. X
  726. X    default:
  727. X        return (Map && isupper(ch)) ? tolower(ch) : ch;
  728. X    }
  729. X    } /* while */
  730. X    return EOF;
  731. X}
  732. X
  733. Xint
  734. Xcknatstr(str)
  735. X    char *str;
  736. X{
  737. X    /* check that a string represents a positive or 0 number */
  738. X    register char *p = str;
  739. X
  740. X    /* skip leading white space */
  741. X    while (isspace(*p)) p++;
  742. X    if (!*p) return 0;
  743. X
  744. X    /* allow a leading sign */
  745. X    if (*p == '-' || *p == '+') p++;
  746. X    if (!*p) return 0;
  747. X
  748. X    /* now skip digits... */
  749. X    while (isdigit(*p)) p++;
  750. X
  751. X    return (p > str && *p == '\0');
  752. X}
  753. X
  754. X/* you can tell I am tired by the extra end-while etc. comments.
  755. X * wonder if it will work?
  756. X * perhaps if I took my socks off too.
  757. X *
  758. X * Hmm, yeah, that worked.
  759. X */
  760. @@@End of lq-text/src/liblqtext/Defaults.c
  761. echo x - lq-text/src/liblqtext/DocPath.c 1>&2
  762. sed 's/^X//' >lq-text/src/liblqtext/DocPath.c <<'@@@End of lq-text/src/liblqtext/DocPath.c'
  763. X/* DocPath.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
  764. X * This code is NOT in the public domain.
  765. X * See the file COPYRIGHT for full details.
  766. X *
  767. X * $Id: DocPath.c,v 1.5 90/10/06 00:11:53 lee Rel1-10 $
  768. X *
  769. X *
  770. X * $Log:    DocPath.c,v $
  771. X * Revision 1.5  90/10/06  00:11:53  lee
  772. X * Prepared for first beta release.
  773. X * 
  774. X * Revision 1.4  90/10/05  23:43:19  lee
  775. X * Put the debugging in isfile() within ASCIITRACE ifdefs.
  776. X * 
  777. X * Revision 1.3  90/08/29  21:46:32  lee
  778. X * Alpha release.
  779. X * 
  780. X * Revision 1.2  90/08/09  19:16:12  lee
  781. X * *** empty log message ***
  782. X * 
  783. X *
  784. X */
  785. X
  786. X#include "globals.h" /* defines and declarations for database filenames */
  787. X
  788. X#include <sys/types.h>
  789. X#include <sys/stat.h>
  790. X#ifdef BSD
  791. X# include <sys/param.h>
  792. X# define PATH_MAX MAXPATHLEN
  793. X#else /*not BSD*/
  794. X# include <limits.h> /* for PATH_MAX */
  795. X#endif
  796. X#include <stdio.h>
  797. X#include "emalloc.h"
  798. X#include "fileinfo.h"
  799. X
  800. X/** Unix system calls: **/
  801. Xextern int stat();
  802. X/** C Library functions: **/
  803. Xextern int strlen();
  804. Xextern char *strcpy();
  805. X/** Within this file: **/
  806. Xextern int IsDir();
  807. X/** **/
  808. X
  809. X#ifdef ASCIITRACE
  810. Xextern int AsciiTrace;
  811. X#endif
  812. X
  813. Xtypedef struct s_DocPath {
  814. X    char *DirName;
  815. X    struct s_DocPath *Next;
  816. X} t_DocPath;
  817. X
  818. Xstatic t_DocPath *XDocPath = 0;
  819. X
  820. X#ifndef PATH_MAX
  821. X# define PATH_MAX 2048
  822. X#endif
  823. X
  824. Xchar *
  825. X_FindFile(Name)
  826. X    char *Name;
  827. X{
  828. X    int IsFile();
  829. X
  830. X    t_DocPath *p;
  831. X    static char Buffer[PATH_MAX + 3]; /* +1 for "\0" */
  832. X
  833. X    if (!XDocPath) {
  834. X#ifdef ASCIITRACE
  835. X    if (AsciiTrace > 4) {
  836. X        fprintf(stderr, "FindFile(%s) --> %s\n", Name,
  837. X                    IsFile(Name) ? Name : (char *) 0);
  838. X    }
  839. X#endif
  840. X    return IsFile(Name) ? Name : (char *) 0;
  841. X    }
  842. X
  843. X    for (p = XDocPath; p; p = p->Next) {
  844. X    (void) sprintf(Buffer, "%s/%s", p->DirName, Name);
  845. X    if (IsFile(Buffer)) {
  846. X#ifdef ASCIITRACE
  847. X        if (AsciiTrace > 4) {
  848. X        fprintf(stderr, "FindFile(%s) --> %s\n", Name, Buffer);
  849. X        }
  850. X#endif
  851. X        return Buffer;
  852. X    }
  853. X    }
  854. X
  855. X    return (char*) 0;
  856. X}
  857. X
  858. Xint
  859. XMakeDocPath(Path)
  860. X    char *Path;
  861. X{
  862. X    extern char *getenv();
  863. X
  864. X    char *Start, *End;
  865. X    t_DocPath **dpp;
  866. X
  867. X    if (XDocPath == (t_DocPath *) 0) {
  868. X    dpp = &XDocPath;
  869. X    *dpp = (t_DocPath *) 0;
  870. X
  871. X    /* For each element in DocPath, */
  872. X    for (Start = Path; Start && *Start; Start = End) {
  873. X        char SaveEnd;
  874. X
  875. X        /* find the end of this bit of the path */
  876. X        for (End = Start; *End && *End != ':'; End++)
  877. X        ;
  878. X        
  879. X        if (End == Start) break;
  880. X
  881. X        SaveEnd = (*End);
  882. X        *End = '\0';
  883. X
  884. X        /* if not a directory, delete from path */
  885. X        if (!IsDir(Start)) {
  886. X        *End = SaveEnd;
  887. X        continue;
  888. X        }
  889. X
  890. X        /* add to the linked list */
  891. X        *dpp = (t_DocPath *) emalloc(sizeof(t_DocPath));
  892. X        (*dpp)->DirName = emalloc(strlen(Start) + 1);
  893. X        (void) strcpy((*dpp)->DirName, Start);
  894. X        dpp = &(*dpp)->Next;
  895. X        (*dpp) = (t_DocPath *) 0;
  896. X        if ((*End = SaveEnd) != '\0') {
  897. X        End++;
  898. X        }
  899. X    }
  900. X    }
  901. X    return 0;
  902. X}
  903. X
  904. Xint
  905. XIsDir(Dir)
  906. X    char *Dir;
  907. X{
  908. X    struct stat statbuf;
  909. X
  910. X    if (!Dir || !*Dir) return 0;
  911. X    if (stat(Dir, &statbuf) < 0) return 0;
  912. X    if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
  913. X    return 0;
  914. X    }
  915. X    return 1;
  916. X}
  917. X
  918. Xint
  919. XIsFile(Path)
  920. X    char *Path;
  921. X{
  922. X    struct stat statbuf;
  923. X
  924. X#ifdef ASCIITRACE
  925. X    if (AsciiTrace > 20) {
  926. X    fprintf(stderr, "IsFile(%s)\n", Path);
  927. X    }
  928. X#endif
  929. X    if (stat(Path, &statbuf) < 0) return 0;
  930. X    if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
  931. X    return 0;
  932. X    }
  933. X#ifdef ASCIITRACE
  934. X    if (AsciiTrace > 20) {
  935. X    fprintf(stderr, "\t\tIsFile(%s) returns true.\n", Path);
  936. X    }
  937. X#endif
  938. X    return 1;
  939. X}
  940. @@@End of lq-text/src/liblqtext/DocPath.c
  941. echo x - lq-text/src/liblqtext/FileList.c 1>&2
  942. sed 's/^X//' >lq-text/src/liblqtext/FileList.c <<'@@@End of lq-text/src/liblqtext/FileList.c'
  943. X/* FileList.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
  944. X * This code is NOT in the public domain.
  945. X * See the file COPYRIGHT for full details.
  946. X */
  947. X
  948. X/*
  949. X *
  950. X * FileList -- operations on the list of files.  This is the Document
  951. X * Directory part of NX-Text.
  952. X *
  953. X * $Id: FileList.c,v 1.8 90/10/13 02:39:05 lee Rel1-10 $
  954. X *
  955. X * $Log:    FileList.c,v $
  956. X * Revision 1.8  90/10/13  02:39:05  lee
  957. X * deleted some incorrect code.
  958. X * 
  959. X * Revision 1.7  90/10/13  02:21:03  lee
  960. X * NEEDALIGN stuff
  961. X * 
  962. X * Revision 1.6  90/10/07  20:37:18  lee
  963. X * changed ifdef sparc to ifdef NEEDALIGN
  964. X * 
  965. X * Revision 1.5  90/10/06  00:11:55  lee
  966. X * Prepared for first beta release.
  967. X * 
  968. X * Revision 1.4  90/09/29  23:46:14  lee
  969. X * very minor speedup, and changed a free() to efree().
  970. X * 
  971. X * Revision 1.3  90/09/20  19:11:05  lee
  972. X * deleted unused locking code.
  973. X * removed a sun4-specific memory leak.  Other minor changes.
  974. X * 
  975. X * Revision 1.2  90/08/29  21:46:33  lee
  976. X * Alpha release.
  977. X * 
  978. X * Revision 1.1  90/08/09  19:16:15  lee
  979. X * Initial revision
  980. X * 
  981. X * Revision 2.2  89/10/08  20:29:10  lee
  982. X * Working version of nx-text engine.  Addfile and wordinfo work OK.
  983. X * 
  984. X * Revision 2.1  89/10/02  01:12:08  lee
  985. X * New index format, with Block/WordInBlock/Flags/BytesSkipped info.
  986. X * 
  987. X * Revision 1.2  89/09/16  21:15:54  lee
  988. X * First demonstratable version.
  989. X * 
  990. X * Revision 1.1  89/09/07  21:01:36  lee
  991. X * Initial revision
  992. X * 
  993. X *
  994. X */
  995. X
  996. X#include "globals.h" /* defines and declarations for database filenames */
  997. X
  998. X#include <stdio.h>
  999. X#include <malloc.h>
  1000. X#include <unistd.h>
  1001. X#include <sys/types.h>
  1002. X#include <sys/stat.h>
  1003. X#include <signal.h>
  1004. X#include <errno.h>
  1005. X#include <fcntl.h>
  1006. X#include <string.h>
  1007. X
  1008. X#include "smalldb.h"
  1009. X#include "fileinfo.h"
  1010. X#include "emalloc.h"
  1011. X
  1012. X/** Unix system calls that need to be declared: **/
  1013. Xextern int stat();
  1014. Xextern int open(), close(), creat();
  1015. Xextern void exit();
  1016. Xextern int read(), write();
  1017. Xextern unsigned alarm();
  1018. X/** library functions that need to be declared: */
  1019. Xextern int lockf();
  1020. Xextern unsigned sleep();
  1021. Xextern void perror();
  1022. Xextern long atol();
  1023. X
  1024. X/** other (lqtext) functions **/
  1025. Xt_FID GetNextFID();
  1026. Xt_FileInfo *GetFileInfo();
  1027. X/** **/
  1028. X
  1029. Xt_FID
  1030. XGetMaxFID()
  1031. X{
  1032. X    extern int errno;
  1033. X
  1034. X    int fd;
  1035. X    struct stat StatBuf;
  1036. X    char Buffer[20];
  1037. X
  1038. X    /* ensure that the file is there */
  1039. X    if (stat(FidFile, &StatBuf) == -1) {
  1040. X    return 0;
  1041. X    }
  1042. X
  1043. X    if ((fd = open(FidFile, O_RDWR, 0)) < 0) {
  1044. X    fprintf(stderr, "Warning: Can't open FID file");
  1045. X    return 0;
  1046. X    }
  1047. X
  1048. X    /* Read the file */
  1049. X    if (read(fd, Buffer, (unsigned int) StatBuf.st_size) < 0) {
  1050. X    fprintf(stderr, "Can't read from \"%s\"\n", FidFile);
  1051. X    exit(1);
  1052. X    }
  1053. X
  1054. X    (void) close(fd);
  1055. X
  1056. X    Buffer[StatBuf.st_size] = '\0';
  1057. X
  1058. X    return atol(Buffer);
  1059. X}
  1060. X
  1061. X/*ARGSUSED*/
  1062. Xt_FID
  1063. XGetNextFID(Size)
  1064. X    long Size; /* to let it keep short FIDs for huge files, execpt I don't */
  1065. X{
  1066. X    extern int errno;
  1067. X    extern long atol();
  1068. X    extern long lseek();
  1069. X
  1070. X    int fd;
  1071. X    char Buffer[21];
  1072. X    struct stat StatBuf;
  1073. X    t_FID Result;
  1074. X
  1075. X    /* ensure that the file is there */
  1076. X    if (stat(FidFile, &StatBuf) == -1) {
  1077. X    fprintf(stderr, "Creating FID file \"%s\"\n", FidFile);
  1078. X    if ((fd = creat(FidFile, 02666)) < 0) {
  1079. X        fprintf(stderr, "Can't create FID file \"%s\"\n", FidFile);
  1080. X        exit(1);
  1081. X    }
  1082. X    (void) close(fd);
  1083. X    return GetNextFID(Size);
  1084. X
  1085. X    /*NOTREACHED*/
  1086. X    }
  1087. X
  1088. X    if ((fd = open(FidFile, O_RDWR, 0)) < 0) {
  1089. X    fprintf(stderr, "Can't open FID file");
  1090. X    perror(FidFile);
  1091. X    exit(1);
  1092. X    }
  1093. X
  1094. X    errno = 0;
  1095. X
  1096. X    /* Read the file */
  1097. X    if (read(fd, Buffer, (unsigned int) StatBuf.st_size) < 0) {
  1098. X    fprintf(stderr, "Can't read from \"%s\"\n", FidFile);
  1099. X    exit(1);
  1100. X    }
  1101. X
  1102. X    Buffer[StatBuf.st_size] = '\0';
  1103. X
  1104. X    Result = atol(Buffer);
  1105. X
  1106. X    if (Result == 0L || *Buffer == '-') {
  1107. X    Result = 1L;
  1108. X    }
  1109. X
  1110. X    (void) sprintf(Buffer, "%lu\n", Result + 1);
  1111. X
  1112. X    /* Move to the start of the file and write the now value.
  1113. X     * No need to truncate the file, because it didn't shrink!
  1114. X     */
  1115. X    (void) lseek(fd, 0, 0L);
  1116. X    (void) write(fd, Buffer, (unsigned int) strlen(Buffer));
  1117. X    (void) close(fd);
  1118. X
  1119. X    return Result;
  1120. X}
  1121. X
  1122. Xtypedef struct {
  1123. X    t_FID FID;
  1124. X    time_t DateLastIndexed;
  1125. X    int FilterType;
  1126. X    unsigned NameLength;
  1127. X    char CurrentLocation[1];
  1128. X} t_PhysicalIndexEntry;
  1129. X
  1130. Xt_PhysicalIndexEntry *
  1131. XFileInfo2Phys(FileInfo)
  1132. X    t_FileInfo *FileInfo;
  1133. X{
  1134. X    t_PhysicalIndexEntry *PIE;
  1135. X    register int NameLength;
  1136. X
  1137. X    if (!FileInfo || !FileInfo->Name) return (t_PhysicalIndexEntry *) 0;
  1138. X
  1139. X    NameLength = strlen(FileInfo->Name);
  1140. X
  1141. X    PIE = (t_PhysicalIndexEntry *) emalloc(
  1142. X                sizeof(t_PhysicalIndexEntry) + NameLength + 1);
  1143. X
  1144. X    if (!PIE) return (t_PhysicalIndexEntry *) 0;
  1145. X
  1146. X    PIE->FID = FileInfo->FID;
  1147. X    PIE->DateLastIndexed = FileInfo->Date;
  1148. X    PIE->FilterType = FileInfo->FilterType;
  1149. X    PIE->NameLength = NameLength;
  1150. X    (void) strcpy(PIE->CurrentLocation, FileInfo->Name);
  1151. X    return PIE;
  1152. X}
  1153. X
  1154. Xt_FileInfo *
  1155. XPhys2FileInfo(PIE)
  1156. X    t_PhysicalIndexEntry *PIE;
  1157. X{
  1158. X    t_FileInfo *FileInfo;
  1159. X
  1160. X    if (!PIE || !PIE->NameLength) return (t_FileInfo *) 0;
  1161. X
  1162. X    FileInfo = (t_FileInfo *) emalloc(sizeof(t_FileInfo));
  1163. X    FileInfo->FID = PIE->FID;
  1164. X    FileInfo->Date = PIE->DateLastIndexed;
  1165. X    FileInfo->FilterType = PIE->FilterType;
  1166. X    FileInfo->Stream = (FILE *) 0;
  1167. X    if (PIE->NameLength) {
  1168. X#if 0
  1169. X    char *doc;
  1170. X#endif
  1171. X
  1172. X    FileInfo->Name = emalloc(PIE->NameLength + 1);
  1173. X    (void) strncpy(FileInfo->Name, PIE->CurrentLocation,
  1174. X                            PIE->NameLength);
  1175. X    FileInfo->Name[PIE->NameLength] = '\0';
  1176. X
  1177. X#if 0
  1178. X    /* with this in place, wordinfo spends over 40% of its time
  1179. X     * in stat!
  1180. X     */
  1181. X    if ((doc = FindFile(FileInfo->Name)) != (char *) 0) {
  1182. X        /* hence, we never retrieve non-existent files */
  1183. X        FileInfo->Name = erealloc(FileInfo->Name, strlen(doc) + 1);
  1184. X        (void) strcpy(FileInfo->Name, doc);
  1185. X    }
  1186. X#endif
  1187. X    } else {
  1188. X    FileInfo->Name = (char *) 0;
  1189. X    }
  1190. X
  1191. X    return FileInfo;
  1192. X}
  1193. X
  1194. Xint
  1195. XSaveFileInfo(FileInfo)
  1196. X    t_FileInfo *FileInfo;
  1197. X{
  1198. X    t_PhysicalIndexEntry *PIE;
  1199. X    datum key, data;
  1200. X    DBM *db;
  1201. X    int RetVal;
  1202. X    char Buffer[20];
  1203. X
  1204. X    if (!FileInfo) return -1;
  1205. X
  1206. X    if ((PIE = FileInfo2Phys(FileInfo)) == (t_PhysicalIndexEntry *) 0) {
  1207. X    return -1;
  1208. X    }
  1209. X
  1210. X    if ((db = startdb(FileIndex)) == (DBM *) 0) {
  1211. X    return -1;
  1212. X    }
  1213. X
  1214. X    if (FileInfo->Name && *(FileInfo->Name)) {
  1215. X    /* For the reverse mapping, FileName --> FID ... store an
  1216. X     * entry of the form ([\377]317, "hello").
  1217. X     * This scheme simply has to go.
  1218. X     * I favour a btree, but that may be needlessly complex.
  1219. X     */
  1220. X    int KeyLen = strlen(FileInfo->Name);
  1221. X    key.dptr = emalloc(KeyLen + 2); /* +2: "\375" and \0 */
  1222. X    /* Note: the N= is so that a file called "123" does not cause
  1223. X     * confusion with the reverse mapping
  1224. X     */
  1225. X    *(key.dptr) = '\375';
  1226. X    (void) strcpy(&(key.dptr[1]), FileInfo->Name);
  1227. X    key.dsize = KeyLen + 1;
  1228. X        /* length of name + length of "\375" -- the nul at the end
  1229. X         * is not included.
  1230. X         */
  1231. X
  1232. X    (void) sprintf(Buffer, "%lu", FileInfo->FID);
  1233. X    data.dptr = Buffer;
  1234. X    data.dsize = strlen(Buffer);
  1235. X    (void) dbm_store(db, key, data, DBM_REPLACE);
  1236. X    (void) efree(key.dptr);
  1237. X    }
  1238. X
  1239. X    (void) sprintf(Buffer, "F%lu", FileInfo->FID);
  1240. X
  1241. X    key.dptr = Buffer;
  1242. X    key.dsize = strlen(Buffer);
  1243. X
  1244. X    data.dptr = (char *) PIE;
  1245. X    data.dsize = sizeof(t_PhysicalIndexEntry) + PIE->NameLength;
  1246. X
  1247. X    RetVal = dbm_store(db, key, data, DBM_REPLACE);
  1248. X
  1249. X    enddb(db);
  1250. X
  1251. X    return RetVal;
  1252. X}
  1253. X
  1254. Xt_FID
  1255. XName2FID(Name)
  1256. X    char *Name;
  1257. X{
  1258. X    DBM *db;
  1259. X    datum key, result;
  1260. X    extern long atol();
  1261. X
  1262. X    key.dsize = strlen(Name);
  1263. X    /* see previous routine for comments about this +2 ugliness */
  1264. X    key.dptr = emalloc(key.dsize + 2);
  1265. X    *(key.dptr) = '\375';
  1266. X    (void) strcpy(&(key.dptr[1]), Name);
  1267. X    key.dsize += 1; /* for the cookie; we don't include the \0 */
  1268. X
  1269. X    if ((db = startdb(FileIndex)) == (DBM *) 0) {
  1270. X    fprintf(stderr, "Name2FID can't get FID for %s (database \"%s\"\n", Name, FileIndex);
  1271. X    (void) efree(key.dptr);
  1272. X    return -1;
  1273. X    }
  1274. X    result = dbm_fetch(db, key);
  1275. X    enddb(db);
  1276. X
  1277. X    (void) efree(key.dptr);
  1278. X
  1279. X    return (result.dsize == 0) ? (t_FID) 0 : atol(result.dptr);
  1280. X}
  1281. X
  1282. Xt_FileInfo *
  1283. XGetFileInfo(FID)
  1284. X    t_FID FID;
  1285. X{
  1286. X    t_FileInfo *FileInfo;
  1287. X    datum key, data;
  1288. X    DBM *db;
  1289. X    char Buffer[20];
  1290. X#ifdef NEEDALIGN
  1291. X    t_PhysicalIndexEntry *PIE;
  1292. X#endif
  1293. X
  1294. X    (void) sprintf(Buffer, "F%lu", FID);
  1295. X    key.dptr = Buffer;
  1296. X    key.dsize = strlen(Buffer);
  1297. X
  1298. X    if ((db = startdb(FileIndex)) == (DBM *) 0) {
  1299. X    return (t_FileInfo *) 0;
  1300. X    }
  1301. X
  1302. X    data = dbm_fetch(db, key);
  1303. X    enddb(db);
  1304. X
  1305. X    if (data.dsize == 0) {
  1306. X    return (t_FileInfo *) 0;
  1307. X    }
  1308. X
  1309. X#ifdef NEEDALIGN
  1310. X    PIE = (t_PhysicalIndexEntry *) emalloc(data.dsize + 1);
  1311. X    (void) memcpy((char *) PIE, data.dptr, data.dsize);
  1312. X    FileInfo = Phys2FileInfo(PIE);
  1313. X    (void) efree((char *) PIE);
  1314. X#else
  1315. X
  1316. X    /* Now we have a PIE, so we need a FileInfo... */
  1317. X    FileInfo = Phys2FileInfo(/*NOSTRICT*/(t_PhysicalIndexEntry *) data.dptr);
  1318. X#endif
  1319. X
  1320. X    return FileInfo;
  1321. X}
  1322. X
  1323. Xint
  1324. Xstrcontains(ShortString, LongString)
  1325. X    char *ShortString;
  1326. X    char *LongString;
  1327. X{
  1328. X    register char *p;
  1329. X
  1330. X    int strprefix();
  1331. X
  1332. X    for (p = LongString; *p; p++) {
  1333. X    if (*p == *ShortString && strprefix(ShortString, p)) {
  1334. X        return 1;
  1335. X    }
  1336. X    }
  1337. X    return 0;
  1338. X}
  1339. X
  1340. Xint
  1341. Xstrprefix(Prefix, String)
  1342. X    register char *Prefix;
  1343. X    register char *String;
  1344. X{
  1345. X    while (*String++ == *Prefix++)
  1346. X    if (!*Prefix) return 1;
  1347. X    return 0;
  1348. X}
  1349. @@@End of lq-text/src/liblqtext/FileList.c
  1350. echo x - lq-text/src/liblqtext/FilterType.c 1>&2
  1351. sed 's/^X//' >lq-text/src/liblqtext/FilterType.c <<'@@@End of lq-text/src/liblqtext/FilterType.c'
  1352. X/* FilterType.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
  1353. X * This code is NOT in the public domain.
  1354. X * See the file COPYRIGHT for full details.
  1355. X */
  1356. X
  1357. X/* FilterType -- determine how to deal with a given file.
  1358. X * Part of Liam Quin's NX-Text text retrieval package.
  1359. X *
  1360. X * $Id: FilterType.c,v 1.6 90/10/06 00:11:56 lee Rel1-10 $
  1361. X *
  1362. X * $Log:    FilterType.c,v $
  1363. X * Revision 1.6  90/10/06  00:11:56  lee
  1364. X * Prepared for first beta release.
  1365. X * 
  1366. X * Revision 1.5  90/09/24  21:20:31  lee
  1367. X * changed a free() to an efree() -- the last one!
  1368. X * 
  1369. X * Revision 1.4  90/09/20  20:07:35  lee
  1370. X * fixed a tiny memory hole...
  1371. X * 
  1372. X * Revision 1.3  90/08/29  21:46:35  lee
  1373. X * Alpha release.
  1374. X * 
  1375. X * Revision 1.2  90/08/09  19:16:18  lee
  1376. X * BSD lint and fixes...
  1377. X * 
  1378. X * Revision 2.2  89/10/08  20:44:34  lee
  1379. X * Working version of nx-text engine.  Addfile and wordinfo work OK.
  1380. X * 
  1381. X *
  1382. X */
  1383. X
  1384. X#include <stdio.h>
  1385. X#include <malloc.h>
  1386. X#include "emalloc.h"
  1387. X#include <sys/types.h>
  1388. X#include <sys/stat.h>
  1389. X#include <errno.h>
  1390. X#include <fcntl.h>
  1391. X#include <string.h>
  1392. X#include <ctype.h>
  1393. X
  1394. X#include "fileinfo.h"
  1395. X#define FILTERDEF /* see filter.h */
  1396. X#include "filter.h"
  1397. X#include "wordrules.h" /* for min word length -- don't index files shorter */
  1398. X
  1399. X#define Prefix(pref,str) ((*(pref)==(*str))&&!strncmp(pref,str,strlen(pref)))
  1400. X
  1401. Xextern int open(), close();
  1402. Xextern int read();
  1403. Xextern int strcontains();
  1404. X
  1405. X/* The current filter types are:
  1406. X * FTYPE_NEWS  1
  1407. X * FTYPE_MAIL  2
  1408. X * FTYPE_CDMS  3
  1409. X * FTYPE_MOSTLYASCII 4
  1410. X * FTYPE_C_SOURCE 5
  1411. X */
  1412. X
  1413. X/* InitFilterTable might one day be called from Defaults.c....
  1414. X * At which point, it will read an ascii file that describes the
  1415. X * various filters, I suppose.
  1416. X *
  1417. X * For,now, it does nothing.  It is only called once, and should return 0
  1418. X * for success or -1 for failure.
  1419. X */
  1420. Xint
  1421. XInitFilterTable()
  1422. X{
  1423. X    return 0;
  1424. X}
  1425. X
  1426. Xint
  1427. XGetFilterType(FileInfo, StatBuf)
  1428. X    t_FileInfo *FileInfo;
  1429. X    struct stat *StatBuf;
  1430. X{
  1431. X    int Type = MaxFilterType + 1;
  1432. X    char Buffer[1024];
  1433. X    int fd = (-1); /* initialised for lint */
  1434. X    int AmountRead = 0; /* initialised for lint */
  1435. X    int ch;
  1436. X    int Length;
  1437. X    FILE *fp = (FILE *) 0;
  1438. X
  1439. X    /* GetFilterType() is called to determine which input filter (if any)
  1440. X     * should be used to read a given file.
  1441. X     * This routine should know about compressed files.
  1442. X     *
  1443. X     * It currently knows about mail, news and C files.
  1444. X     * There are also hooks for CDMS files (a word-processing package).
  1445. X     *
  1446. X     * If the file should not be indexed at all (e.g. it's a core dump),
  1447. X     * we return -1.
  1448. X     */
  1449. X
  1450. X    if (!FileInfo || !FileInfo->Name || !*(FileInfo->Name)) return (-1);
  1451. X
  1452. X    if (StatBuf->st_size < MinWordLength) return (-1);
  1453. X
  1454. X    Length = strlen(FileInfo->Name);
  1455. X
  1456. X    if (FileInfo->Name[Length - 1] == 'Z' && Length > 2 &&
  1457. X                    FileInfo->Name[Length - 2] == '.') {
  1458. X    char *Buf = emalloc(Length + 10);
  1459. X
  1460. X    (void) sprintf(Buf, "zcat < \"%s\"", FileInfo->Name);
  1461. X
  1462. X    fp = popen(Buf, "r");
  1463. X    (void) efree(Buf);
  1464. X    if (fp == (FILE *) 0) {
  1465. X        return (-1);
  1466. X    }
  1467. X    }
  1468. X
  1469. X    if (fp) {
  1470. X    if ((AmountRead = fread(fp, Buffer, sizeof(Buffer))) < MinWordLength) {
  1471. X        (void) pclose(fp);
  1472. X        fp = (FILE *) 0; /* try again with read() */
  1473. X    }
  1474. X    }
  1475. X
  1476. X    if (!fp) {
  1477. X    if ((fd = open(FileInfo->Name, O_RDONLY, 0)) < 0) {
  1478. X        return -1;
  1479. X    }
  1480. X    if ((AmountRead = read(fd, Buffer, sizeof(Buffer)-1)) < MinWordLength) {
  1481. X        (void) close(fd);
  1482. X        return -1;
  1483. X    }
  1484. X    }
  1485. X    if (fp) {
  1486. X    (void) pclose(fp);
  1487. X    } else {
  1488. X    (void) close(fd);
  1489. X    }
  1490. X
  1491. X    /* Check the magic table for CDMS: */
  1492. X    if ((unsigned char) Buffer[0] == 128 && Buffer[1] == 'M') {
  1493. X    if (AmountRead > 35) { /* size of CDMS file header */
  1494. X        Type = FTYPE_CDMS;
  1495. X        return (FileInfo->FilterType = Type);
  1496. X    }
  1497. X    }
  1498. X     
  1499. X    if (AmountRead < 30) {
  1500. X    register char *p = Buffer;
  1501. X
  1502. X    /* who cares if it's this small? */
  1503. X    for (; p - Buffer < AmountRead; p++) {
  1504. X        if (!isascii(*p)) {
  1505. X        return (-1);
  1506. X        }
  1507. X    }
  1508. X    return 0;
  1509. X    }
  1510. X
  1511. X    /* Not cdms -- try news/mail;
  1512. X     * mail files start with From;
  1513. X     * news starts with From, Path or Relay-Version
  1514. X     */
  1515. X    if (isupper(Buffer[0])) {
  1516. X    Buffer[AmountRead] = '\0';
  1517. X    AmountRead--;
  1518. X    if (Prefix("Xref: ", Buffer)) {
  1519. X        return (FileInfo->FilterType = FTYPE_NEWS);
  1520. X    } else if (Prefix("Newsgroups: ", Buffer)) {
  1521. X        return (FileInfo->FilterType = FTYPE_NEWS);
  1522. X    } else if (Prefix("Relay-Version: ", Buffer)) {
  1523. X        return (FileInfo->FilterType = FTYPE_NEWS);
  1524. X    } else if (Prefix("From", Buffer)) {
  1525. X        if (strcontains("\nPath: ", Buffer)) {
  1526. X        /* bug: should only check header, not body! */
  1527. X        return FTYPE_NEWS;
  1528. X        } else {
  1529. X        return FTYPE_MAIL;
  1530. X        }
  1531. X    } else if (Prefix("Path: ", Buffer)) {
  1532. X        if (strcontains("\nNewsgroups: ", Buffer)) {
  1533. X        return FTYPE_NEWS;
  1534. X        } else {
  1535. X        return FTYPE_MAIL;
  1536. X        }
  1537. X    } else if (Prefix("Return-Path: ", Buffer)) {
  1538. X        return FTYPE_MAIL; /* MH-style mail */
  1539. X    }
  1540. X    }
  1541. X
  1542. X    /* look for C, trying not to get muddled up with shell scripts */
  1543. X    ch = FileInfo->Name[Length - 1];
  1544. X
  1545. X    if ((ch == 'c' || ch == 'h') && (Length > 2) &&
  1546. X                FileInfo->Name[Length - 2] == '.') {
  1547. X    /* We could require one of
  1548. X     * . a comment
  1549. X     * . a #[ ^i]*(include|define|ifn?def|if)[ ^i]+
  1550. X     * . main[ ^i\n]*(
  1551. X     * . a declaration -- int, char, long, unsigned, static
  1552. X     * in the first block of the file.
  1553. X     * Can't be bothered today.
  1554. X     */
  1555. X    if (strcontains("#line", Buffer)) {
  1556. X        return (-1); /* preprocessed already, index the original! */
  1557. X        /* we ought to say why we are not indexing it! */
  1558. X    }
  1559. X
  1560. X    /* we are very predisposed to thinking of this as C... */
  1561. X    if (Prefix("#include", Buffer)        ||
  1562. X        strcontains("/*", Buffer)        ||
  1563. X        strcontains("#define", Buffer)    ||
  1564. X        strcontains("argc", Buffer)        ||
  1565. X        strcontains("()", Buffer)        ||
  1566. X        strcontains("#include", Buffer)) {
  1567. X        return FTYPE_C_SOURCE;
  1568. X    }
  1569. X    }
  1570. X
  1571. X    /* if still not done, choose between Don't Index and Ascii Filter
  1572. X     * (which simply strips non-ascii characters).
  1573. X     */
  1574. X    if (Type >= MaxFilterType) {
  1575. X    register char *p;
  1576. X    int AsciiCount = 0;
  1577. X    int OtherCount = 0;
  1578. X
  1579. X    for (p = Buffer; p - Buffer < AmountRead; p++) {
  1580. X        if (isascii(*p)) AsciiCount++;
  1581. X        else OtherCount++;
  1582. X        if (!*p) {
  1583. X        /* If it has nulls in it, it isn't a normal file,
  1584. X         * and we have no idea what to do with it!
  1585. X         * (if we did know, it would have had a magic number,
  1586. X         * so we wouldn't have got here)
  1587. X         */
  1588. X        Type = (-1);
  1589. X        break;
  1590. X        }
  1591. X        if (Type > 0) {
  1592. X        if (AsciiCount > OtherCount * 5) {
  1593. X            Type = (OtherCount) ? FTYPE_MOSTLYASCII : 0;
  1594. X        } else {
  1595. X            Type = (-1); /* too much garbage */
  1596. X        }
  1597. X        }
  1598. X    }
  1599. X    }
  1600. X
  1601. X    if (Type > MaxFilterType) Type = -1; /* don't index */
  1602. X    return Type;
  1603. X}
  1604. @@@End of lq-text/src/liblqtext/FilterType.c
  1605. echo x - lq-text/src/liblqtext/Makefile 1>&2
  1606. sed 's/^X//' >lq-text/src/liblqtext/Makefile <<'@@@End of lq-text/src/liblqtext/Makefile'
  1607. X# Makefile for LQ-Text, a full text retrieval package by Liam R. Quin
  1608. X#
  1609. X# This Makefile belongs in the src/liblqtext directory.
  1610. X# Note that most of the actual configuration is done in ../Makefile and
  1611. X# in ../h/global.h, and not here.  This file is for representing the
  1612. X# dependancies between source components and specifying the steps
  1613. X# required to build the library $(DESTDIR)/$(TEXTLIB)
  1614. X#
  1615. X# $Id: Makefile,v 1.3 90/10/06 00:06:22 lee Rel1-10 $
  1616. X#
  1617. X# $Log:    Makefile,v $
  1618. X# Revision 1.3  90/10/06  00:06:22  lee
  1619. X# deleted mkdep output.
  1620. X# 
  1621. X# Revision 1.2  90/09/29  23:48:33  lee
  1622. X# does cmp on the right file now...
  1623. X# 
  1624. X# Revision 1.1  90/08/09  19:17:07  lee
  1625. X# Initial revision
  1626. X# 
  1627. X# 
  1628. X#
  1629. X
  1630. XPWD=liblqtext
  1631. X
  1632. XTEXTLIB=liblqtext.a
  1633. XLIAMLIB=liblq.a
  1634. XDESTDIR=../lib
  1635. XRANLIB=ranlib
  1636. XTEXTLINTLIB=llib-llqtext.ln
  1637. XLIAMLINTLIB=llib-llq.ln
  1638. XLINT=lint
  1639. XLINTFLAGS=-a -b -c -h -x 
  1640. X
  1641. XEXTRA=-I../h
  1642. X
  1643. Xall: $(DESTDIR)/$(TEXTLIB) $(DESTDIR)/$(LIAMLIB)
  1644. X
  1645. Xinstall: all
  1646. X
  1647. Xlint: $(DESTDIR)/$(TEXTLINTLIB) $(DESTDIR)/$(LIAMLINTLIB)
  1648. X    -echo The lint libraries are up to date.
  1649. X
  1650. X$(DESTDIR)/$(TEXTLINTLIB): $(TEXTLINTLIB)
  1651. X    mv $(TEXTLINTLIB) $(DESTDIR)/$(TEXTLINTLIB)
  1652. X
  1653. X$(DESTDIR)/$(LIAMLINTLIB): $(LIAMLINTLIB)
  1654. X    mv $(LIAMLINTLIB) $(DESTDIR)/$(LIAMLINTLIB)
  1655. X
  1656. XNDBMCFILES=
  1657. XNDBMOFILES=
  1658. X
  1659. X## keep all of the following consistent: ###################################
  1660. X
  1661. XTEXTOBJS = WordInfo.o DocPath.o Defaults.o FileList.o Phrase.o Root.o \
  1662. X              numbers.o pblock.o smalldb.o system.o FilterType.o \
  1663. X              asciitrace.o $(NDBMOFILES)
  1664. X
  1665. XTEXTSRC = DocPath.c Defaults.c FileList.c Phrase.c Root.c WordInfo.c \
  1666. X              malloc.c numbers.c pblock.c smalldb.c system.c FilterType.c \
  1667. X              asciitrace.c $(NDBMCFILES)
  1668. X
  1669. XLIAMOBJS = malloc.o progname.o cmdname.o
  1670. XLIAMSRC = malloc.c progname.c cmdname.c
  1671. X
  1672. X## end of mutually related stuff  ##########################################
  1673. X
  1674. X$(TEXTLINTLIB): $(TEXTSRC)
  1675. X    $(LINT) -Clqtext $(LINTFLAGS) $(CFLAGS) $(TEXTSRC)
  1676. X
  1677. Xsaber_src:
  1678. X    #cd $(PWD)
  1679. X    #load $(CFLAGS) $(TEXTSRC) $(LIAMSRC)
  1680. X    #cd ..
  1681. X
  1682. Xsaber_obj:
  1683. X    #cd $(PWD)
  1684. X    #load $(CFLAGS) $(TEXTOBJS) $(LIAMOBJS)
  1685. X    #cd ..
  1686. X
  1687. X$(LIAMLINTLIB): $(LIAMSRC)
  1688. X    $(LINT) -Clq $(LINTFLAGS) $(CFLAGS) $(LIAMSRC)
  1689. X
  1690. X$(DESTDIR)/$(TEXTLIB): $(TEXTLIB)
  1691. X    -test -d $(DESTDIR) || mkdir $(DESTDIR)
  1692. X    -test -f $(DESTDIR)/$(TEXTLIB) || cp /dev/null $(DESTDIR)/$(TEXTLIB)
  1693. X    -( cmp $(TEXTLIB) $(DESTDIR)/$(TEXTLIB) || cp $(TEXTLIB) $(DESTDIR) )
  1694. X    -/bin/rm -f $(TEXTLIB)
  1695. X
  1696. X$(DESTDIR)/$(LIAMLIB): $(LIAMLIB)
  1697. X    -test -d $(DESTDIR) || mkdir $(DESTDIR)
  1698. X    -test -f $(DESTDIR)/$(LIAMLIB) || cp /dev/null $(DESTDIR)/$(LIAMLIB)
  1699. X    -( cmp $(LIAMLIB) $(DESTDIR)/$(LIAMLIB) || cp $(LIAMLIB) $(DESTDIR) )
  1700. X    -/bin/rm -f $(LIAMLIB)
  1701. X
  1702. X$(TEXTLIB): $(TEXTOBJS)
  1703. X    rm -f $(TEXTLIB)
  1704. X    ar rv $(TEXTLIB) $(TEXTOBJS)
  1705. X    $(RANLIB) $(TEXTLIB)
  1706. X
  1707. X$(LIAMLIB): $(LIAMOBJS)
  1708. X    rm -f $(LIAMLIB)
  1709. X    ar rv $(LIAMLIB) $(LIAMOBJS)
  1710. X    $(RANLIB) $(LIAMLIB)
  1711. X
  1712. Xtidy:
  1713. X    /bin/rm -f *.o core
  1714. X
  1715. Xclean: tidy
  1716. X    /bin/rm -f $(TARGETS) $(TEST)
  1717. X
  1718. Xdepend:
  1719. X    mkdep $(CFLAGS) *.c
  1720. X
  1721. X# DO NOT DELETE THIS LINE -- mkdep uses it.
  1722. X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
  1723. X
  1724. X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
  1725. @@@End of lq-text/src/liblqtext/Makefile
  1726. echo end of part 03
  1727. -- 
  1728. Liam R. E. Quin,  lee@sq.com, SoftQuad Inc., Toronto, +1 (416) 963-8337
  1729.